#include <iostream>
#include <sys/timerfd.h>
#include <unistd.h>
#include <functional>
#include <vector>
#include <memory>
#include <unordered_map>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
private:
    uint64_t _id;         // 定时任务对象ID
    uint32_t _timeout;    // 定时任务的超时时间
    TaskFunc _task_cb;    // 定时器对象要执行的定时任务
    ReleaseFunc _release; // 用于删除TimeWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id, uint32_t timeout, TaskFunc cb) : _id(id), _timeout(timeout), _task_cb(cb) {}
    ~TimerTask()
    {
        _task_cb();
        _release();
    }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
    uint32_t DelayTime() { return _timeout; }
};

class TimerWheel
{
private:
    using PtrTask = std::shared_ptr<TimerTask>;
    using WeakTask = std::weak_ptr<TimerTask>;
    int _tick;     // 当前的秒针，走到哪里释放哪里，释放哪里，就相当于执行哪里的任务
    int _capacity; // 表盘最大数量--最大的延迟时间
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;

    void remove(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}
    // 添加定时任务
    void Timeradd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        // 60s以上和0s以下的定时任务不⽀持
        if (delay > _capacity || delay <= 0)
            return;
        PtrTask task(new TimerTask(id, delay, cb));
        task->SetRelease(std::bind(&TimerWheel::remove, this, id));
        _timers[id] = WeakTask(task);
        _wheel[(_tick + delay) % _capacity].push_back(task);
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return; // 没找到，没法刷新
        }
        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理对象的shared_ptr
        uint32_t delay = pt->DelayTime();
        _wheel[(_tick + delay) % _capacity].push_back(pt);
    }

    // 这个函数应该每秒钟被执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组，就会把数组中保存的所有管理定时对象shared_ptr释放
    }
};

class TestTime
{
public:
    TestTime()
    {
        std::cout << "构造" << std::endl;
    }
    ~TestTime()
    {
        std::cout << "析构" << std::endl;
    }
};

void del(TestTime *tt)
{
    delete tt;
}

int main()
{
    TimerWheel tw;
    TestTime *t = new TestTime();
    tw.Timeradd(80, 5, std::bind(del, t));
    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(80);
        std::cout << "刷新了⼀下80号定时任务!\n";
        tw.RunTimerTask();// 每秒调⽤⼀次，模拟定时器
    }
    std::cout << "刷新定时任务停⽌, 5s后释放任务将被执⾏\n";
    while (1)
    {
        std::cout << "--------------------\n";
        sleep(1);
        tw.RunTimerTask(); // 每秒调⽤⼀次，模拟定时器
    }
    return 0;
}